import { arrayMethods } from './array.js'
import Dep from './dep'
class Observer{
    constructor(data){
        this.dep = new Dep()
        //  data.__ob__ = this  这样写__ob__属性也会被监测，而且后面还会循环递归监测它，陷入死循环
        Object.defineProperty(data,'__ob__',{
            value: this,
            enumerable: false // 不可枚举
        })
        if(Array.isArray(data)){
            data.__proto__ = arrayMethods
            this.observeArray(data)
        }else{
            this.walk(data)
        }
    }
    observeArray(data){
        data.forEach((item)=>{
            observe(item)
        })
    }
    walk(data){
        const keys = Object.keys(data)
        keys.forEach((key)=>{
            defineReactive(data,key,data[key])
        })
    }
}

function defineReactive(data,key,value){
    let childOb = observe(value)
    const dep = new Dep()
    Object.defineProperty(data,key,{
        get(){
            if(Dep.target){
                dep.depend()
                if(childOb){
                    childOb.dep.depend()
                }
                if(Array.isArray(value)){
                    dependArray(value)
                }
            }
            return value
        },
        set(newVal){
            if(newVal !== value){
                observe(newVal)
                value = newVal
                dep.notify()
            }
        }
    })
}

function dependArray(arr){
    arr.forEach((item)=>{
        item.__ob__ && item.__ob__.dep.depend()
        if(Array.isArray(item)){
            dependArray(item)
        }
    })
}


export function observe(data){
    if(data.__ob__){
        return
    }
    if(typeof data === 'object' && data !== null){
        return new Observer(data)
    }
}